import { Buffer } from "buffer";
import { GolombParse } from "./Golomb_Parse";

//ffmpeg
const AV_PIX_FMT_YUV420P: number = 0;
const AV_PIX_FMT_YUV422P: number = 4;
const AV_PIX_FMT_YUV444P: number = 5;
const AV_PIX_FMT_GRAY8: number = 8;

// let sps: Buffer = Buffer.from('Z00AKp2oHgCJ+WbgICAoAAAfQAAGGoQgAA==','base64');
// console.log(sps.toString('hex'));

class H264_Parse {
    private data:GolombParse;
    constructor(srcData: Buffer) {
        this.data = new GolombParse(srcData);
    }
    private map_pixel_format(chroma_format_idc: number/*,bit_depth:number*/): number {
        let pix_fmt: number = 0;
        // switch (bit_depth) {
        //     case 8:
        if (chroma_format_idc == 0) pix_fmt = AV_PIX_FMT_GRAY8;
        if (chroma_format_idc == 1) pix_fmt = AV_PIX_FMT_YUV420P;
        if (chroma_format_idc == 2) pix_fmt = AV_PIX_FMT_YUV422P;
        if (chroma_format_idc == 3) pix_fmt = AV_PIX_FMT_YUV444P;
        //         break;
        //     case 9:
        //         if (chroma_format_idc == 0) pix_fmt = AV_PIX_FMT_GRAY16;
        //         if (chroma_format_idc == 1) pix_fmt = AV_PIX_FMT_YUV420P9;
        //         if (chroma_format_idc == 2) pix_fmt = AV_PIX_FMT_YUV422P9;
        //         if (chroma_format_idc == 3) pix_fmt = AV_PIX_FMT_YUV444P9;
        //         break;
        //     case 10:
        //         if (chroma_format_idc == 0) pix_fmt = AV_PIX_FMT_GRAY10;
        //         if (chroma_format_idc == 1) pix_fmt = AV_PIX_FMT_YUV420P10;
        //         if (chroma_format_idc == 2) pix_fmt = AV_PIX_FMT_YUV422P10;
        //         if (chroma_format_idc == 3) pix_fmt = AV_PIX_FMT_YUV444P10;
        //         break;
        //     case 12:
        //         if (chroma_format_idc == 0) pix_fmt = AV_PIX_FMT_GRAY12;
        //         if (chroma_format_idc == 1) pix_fmt = AV_PIX_FMT_YUV420P12;
        //         if (chroma_format_idc == 2) pix_fmt = AV_PIX_FMT_YUV422P12;
        //         if (chroma_format_idc == 3) pix_fmt = AV_PIX_FMT_YUV444P12;
        //         break;
        //     default:
        //         console.log("The following bit-depths are currently specified: 8, 9, 10 and 12 bits");
        //         return AVERROR_INVALIDDATA;
        // }
        return pix_fmt;
    }
    public PaeseSPS(): any {
        let ret: any = {};
        let forbidden_zero_bit: number = this.data.U(1);
        let nal_ref_idc: number = this.data.U(2);
        let nal_unit_type: number = this.data.U(5);
        if (nal_unit_type == 7) {
            let profile_idc: number = this.data.U(8);
            let constralet_set0_flag: number = this.data.U(1);//(buf[1] & 0x80)>>7;
            let constralet_set1_flag: number = this.data.U(1);//(buf[1] & 0x40)>>6;
            let constralet_set2_flag: number = this.data.U(1);//(buf[1] & 0x20)>>5;
            let constralet_set3_flag: number = this.data.U(1);//(buf[1] & 0x10)>>4;
            let reserved_zero_4bits: number = this.data.U(4);
            let level_idc: number = this.data.U(8);
            let seq_parameter_set_id: number = this.data.UE();
            let chroma_format_idc: number = 1;
            ret.pix_fmt = this.map_pixel_format(chroma_format_idc);
            if (profile_idc == 100 || profile_idc == 110 ||
                profile_idc == 122 || profile_idc == 144) {
                chroma_format_idc = this.data.UE();
                ret.pix_fmt = this.map_pixel_format(chroma_format_idc);
                if (chroma_format_idc == 3) {
                    let residual_colour_transform_flag: number = this.data.U(1);
                }
                let bit_depth_luma_minus8: number = this.data.UE();
                let bit_depth_chroma_minus8: number = this.data.UE();
                let qpprime_y_zero_transform_bypass_flag: number = this.data.U(1);
                let seq_scaling_matrix_present_flag: number = this.data.U(1);

                let seq_scaling_list_present_flag = new Array<number>(8);
                if (1 == seq_scaling_matrix_present_flag) {
                    for (let i = 0; i < 8; i++)
                    {
                        seq_scaling_list_present_flag[i] = this.data.U(1);
                    }
                }
            }
            let log2_max_frame_num_minus4: number = this.data.UE();
            let pic_order_cnt_type: number = this.data.UE();
            if (pic_order_cnt_type == 0) {
                let log2_max_pic_order_cnt_lsb_minus4: number = this.data.UE();
            }
            else if (pic_order_cnt_type == 1) {
                let delta_pic_order_always_zero_flag: number = this.data.U(1);
                let offset_for_non_ref_pic: number = this.data.SE();
                let offset_for_top_to_bottom_field: number = this.data.SE();
                let num_ref_frames_in_pic_order_cnt_cycle: number = this.data.UE();

                let offset_for_ref_frame = new Array<number>(num_ref_frames_in_pic_order_cnt_cycle);
                for (let i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++){
                    offset_for_ref_frame[i] = this.data.SE();
                }
            }
            let num_ref_frames: number = this.data.UE();
            let gaps_in_frame_num_value_allowed_flag: number = this.data.U(1);
            let pic_width_in_mbs_minus1: number = this.data.UE();
            let pic_height_in_map_units_minus1: number = this.data.UE();


            let frame_mbs_only_flag: number = this.data.U(1);//0表示高，1表示高
            if (0 == frame_mbs_only_flag) {
                let mb_adaptive_frame_field_flag: number = this.data.U(1);
            }
            let direct_8x8_inference_flag: number = this.data.U(1);
            let frame_cropping_flag: number = this.data.U(1);

            let frame_crop_left_offset: number = 0;
            let frame_crop_right_offset: number = 0;
            let frame_crop_top_offset: number = 0;
            let frame_crop_bottom_offset: number = 0;

            if (1 == frame_cropping_flag) {
                frame_crop_left_offset = this.data.UE();
                frame_crop_right_offset = this.data.UE();
                frame_crop_top_offset = this.data.UE();
                frame_crop_bottom_offset = this.data.UE();
            }
            let vui_parameter_present_flag: number = this.data.U(1);
            if (1 == vui_parameter_present_flag) {
                let aspect_ratio_info_present_flag: number = this.data.U(1);
                if (1 == aspect_ratio_info_present_flag) {
                    let aspect_ratio_idc: number = this.data.U(8);
                    if (aspect_ratio_idc == 255) {
                        let sar_width: number = this.data.U(16);
                        let sar_height: number = this.data.U(16);
                    }
                }
                let overscan_info_present_flag: number = this.data.U(1);
                if (1 == overscan_info_present_flag) {
                    let overscan_appropriate_flagu: number = this.data.U(1);
                }
                let video_signal_type_present_flag: number = this.data.U(1);
                if (1 == video_signal_type_present_flag) {
                    let video_format: number = this.data.U(3);
                    let video_full_range_flag: number = this.data.U(1);
                    let colour_description_present_flag: number = this.data.U(1);
                    if (1 == colour_description_present_flag) {
                        let colour_primaries: number = this.data.U(8);
                        let transfer_characteristics: number = this.data.U(8);
                        let matrix_coefficients: number = this.data.U(8);
                    }
                }
                let chroma_loc_info_present_flag: number = this.data.U(1);
                if (1 == chroma_loc_info_present_flag) {
                    let chroma_sample_loc_type_top_field: number = this.data.UE();
                    let chroma_sample_loc_type_bottom_field: number = this.data.UE();
                }
                let timing_info_present_flag: number = this.data.U(1);

                if (1 == timing_info_present_flag) {
                    let num_units_in_tick: number = this.data.U(32);
                    let time_scale: number = this.data.U(32);
                    let fixed_frame_rate_flag: number = this.data.U(1);
                }

            }

            // 宽高计算公式
            ret.width = (pic_width_in_mbs_minus1 + 1) * 16;
            ret.height = (2 - frame_mbs_only_flag) * (pic_height_in_map_units_minus1 + 1) * 16;

            if (1 == frame_cropping_flag) {
                let crop_unit_x: number;
                let crop_unit_y: number;
                if (0 == chroma_format_idc) // monochrome
                {
                    crop_unit_x = 1;
                    crop_unit_y = 2 - frame_mbs_only_flag;
                }
                else if (1 == chroma_format_idc) // 4:2:0
                {
                    crop_unit_x = 2;
                    crop_unit_y = 2 * (2 - frame_mbs_only_flag);
                }
                else if (2 == chroma_format_idc) // 4:2:2
                {
                    crop_unit_x = 2;
                    crop_unit_y = 2 - frame_mbs_only_flag;
                }
                else // 3 == sps.chroma_format_idc   // 4:4:4
                {
                    crop_unit_x = 1;
                    crop_unit_y = 2 - frame_mbs_only_flag;
                }

                ret.width -= crop_unit_x * (frame_crop_left_offset + frame_crop_right_offset);
                ret.height -= crop_unit_y * (frame_crop_top_offset + frame_crop_bottom_offset);
            }
            return ret;
        } else {
            return ret;
        }
    }
}

export function getH264SPSInfo(sps: Buffer): any {
    let parse = new H264_Parse(sps);
    let info = parse.PaeseSPS();
    return info;
}


export const H264CodecID:number = 28;